<template>
	<el-form ref="Form" :model="props.formState" label-width="140px">
		<el-form-item
			v-for="item in formData.filter(v => !v.hidden)"
			:key="item.dataIndex"
			:name="item.dataIndex"
			:prop="item.dataIndex"
			:label="item.title"
			:rules="item.rules || []"
		>
			<template v-if="item.type == 'input'">
				<el-input
					v-model="formState[item.dataIndex]"
					clearable
					:placeholder="item.placeholder || ' '"
					:disabled="item.disabled"
					v-bind="item.bind"
					autocomplete="off"
					@input="
						$event => {
							item.input && item.input($event)
						}
					"
					@blur="
						() => {
							item.blur && item.blur(formState[item.dataIndex])
						}
					"
				/>
			</template>
			<template v-else-if="item.type == 'select'">
				<el-select
					v-model="formState[item.dataIndex]"
					class="input"
					clearable
					style="width: 100%"
					v-bind="item.bind"
					:disabled="item.disabled"
					:placeholder="item.placeholder || ' '"
					@change="
						$event => {
							item.change && item.change($event)
						}
					"
				>
					<el-option v-for="option in item.data" :key="option.value" :label="option.label" :value="option.value"> </el-option>
				</el-select>
			</template>
			<template v-else-if="item.type == 'dayTime'">
				<el-date-picker
					v-model="formState[item.dataIndex]"
					clearable
					type="datetime"
					v-bind="item.bind"
					:format="item.format || 'yyyy-MM-dd HH:mm'"
					:value-format="item.format || 'yyyy-MM-dd HH:mm'"
					:disabled="item.disabled"
				/>
			</template>
			<template v-else-if="item.type == 'day'">
				<el-date-picker
					v-model="formState[item.dataIndex]"
					clearable
					style="width: 100%"
					type="date"
					v-bind="item.bind"
					:format="item.format || 'yyyy-MM-dd'"
					:value-format="item.format || 'yyyy-MM-dd'"
					:disabled="item.disabled"
				/>
			</template>
			<template v-else-if="item.type == 'switch'">
				<el-switch
					v-model="formState[item.dataIndex]"
					:active-value="item.active || item.active === 0 ? item.active : true"
					:inactive-value="item.inactive || item.inactive === 0 ? item.inactive : false"
					:active-text="item.activeText || ''"
					:inactive-text="item.inactiveText || ''"
					v-bind="item.bind"
					:disabled="item.disabled"
					@change="
						$event => {
							item.change && item.change($event)
						}
					"
				>
				</el-switch>
			</template>
			<template v-else-if="item.type == 'radio'">
				<el-radio-group v-model="formState[item.dataIndex]" v-bind="item.bind" :disabled="item.disabled" @change="item.change && item.change">
					<el-radio v-for="option in item.data" :key="option.value" :label="option.label" :value="option.value"> </el-radio>
				</el-radio-group>
			</template>
			<template v-else-if="item.type == 'inputNumber'">
				<el-input-number
					v-model="formState[item.dataIndex]"
					v-bind="item.bind"
					:min="item.min || 0"
					:max="item.max || 99"
					:disabled="item.disabled"
				></el-input-number>
			</template>
			<template v-else-if="item.type == 'multiple'">
				<el-select
					v-model="formState[item.dataIndex]"
					v-bind="item.bind"
					clearable
					multiple
					:disabled="item.disabled"
					:placeholder="item.placeholder || ' '"
				>
					<el-option v-for="option in item.data" :key="option.value" :label="option.label" :value="option.value"> </el-option>
				</el-select>
			</template>
			<template v-else-if="item.type == 'cascader'">
				<el-cascader
					v-if="!item.loadData"
					v-model="formState[item.dataIndex]"
					clearable
					:options="item.data"
					:placeholder="item.placeholder || ' '"
					:disabled="item.disabled"
					v-bind="item.bind"
					:props="{
						label: item.label || 'label'
					}"
					style="width: 100%"
					@change="
						$event => {
							item.change && item.change($event)
						}
					"
				/>
				<el-cascader
					v-else
					v-model="formState[item.dataIndex]"
					clearable
					:options="item.data"
					:props="{
						lazy: true,
						lazyLoad: item.loadData,
						label: item.label || 'label'
					}"
					:placeholder="item.placeholder || ' '"
					:disabled="item.disabled"
					v-bind="item.bind"
					style="width: 100%"
					@change="
						$event => {
							item.change && item.change($event)
						}
					"
				/>
			</template>
			<template v-else-if="item.type == 'textarea'">
				<el-input
					style="word-break: break-all"
					v-model="formState[item.dataIndex]"
					type="textarea"
					v-bind="item.bind"
					clearable
					:placeholder="item.placeholder || ' '"
					:rows="item.rows || 2"
					:disabled="item.disabled"
					:show-word-limit="true"
				/>
			</template>
			<template v-else-if="item.type == 'upload'">
				<el-upload :action="action" :show-file-list="false" :before-upload="beforeUpload" @change="handleChange($event, item.dataIndex)">
					<img v-if="formState[item.dataIndex]" :src="formState[item.dataIndex]" />
					<div v-else>
						<i v-if="loading" class="el-icon-loading avatar-uploader-icon"></i>
						<i v-else class="el-icon-plus avatar-uploader-icon"></i>
						<div class="ant-upload-text">点击上传</div>
					</div>
				</el-upload>
			</template>
			<template v-else-if="item.type == 'uploadSys'">
				<el-upload
					class="avatar-uploader"
					:action="action"
					:headers="{ 'Platform-Name': 'platform' }"
					list-type="picture"
					:show-file-list="false"
					:on-success="handleAvatarSuccess"
					:before-upload="beforeUpload"
					:on-remove="handleRemove"
				>
					<img class="avatar" v-if="formState[item.dataIndex]" :src="formState[item.dataIndex]" />

					<el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
				</el-upload>
				<span v-if="formState[item.dataIndex]" class="el-upload-list__item-delete" @click="handleRemove(file)">
					<el-icon :size="16"><Delete /></el-icon>
				</span>
			</template>
			<template v-else-if="item.type == 'select-tree'">
				<el-popover width="30%" :visible="item.visible" placement="bottom-start" trigger="click">
					<template #reference>
						<el-input
							:value="findText(item.data, item.value || 'id', formState[item.dataIndex], item.label) || item.defaultText"
							:readonly="true"
							:placeholder="item.placeholder || ' '"
							:disabled="item.disabled"
							@click.native="item.visible = true"
						>
							<template v-if="!item.disabled" #suffix>
								<svg-icon
									v-if="formState[item.dataIndex] || formState[item.dataIndex] === 0"
									icon="icon-close-circle"
									@click.stop="emit('update:formState', { ...formState, [item.dataIndex]: null })"
								></svg-icon>
							</template>
						</el-input>
					</template>
					<div v-click-outside="() => (item.visible = false)" class="popover">
						<el-tree
							:data="item.data"
							:props="{ label: item.label || 'name', children: 'children' }"
							:node-key="item.value || 'id'"
							highlight-current
							:expand-on-click-node="false"
							:current-node-key="formState[item.dataIndex] ? formState[item.dataIndex] : undefined"
							accordion
							@current-change="
								$event => {
									item.onChange && item.onChange($event)
									item.visible = false
								}
							"
						>
						</el-tree>
					</div>
				</el-popover>
			</template>
			<template v-else-if="item.type == 'tree'">
				<form-tree
					:data="item.data"
					v-model="formState[item.dataIndex]"
					:props="{ label: item.label || 'name', children: 'children', disabled: () => item.disabled }"
					:split="item.split"
					:node-key="item.key || 'id'"
					default-expand-all
					v-bind="item.bind"
					style="width: 100%"
					show-checkbox
				>
				</form-tree>
			</template>
		</el-form-item>
	</el-form>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import formTree from './form-tree.vue'
import { ElMessage, ClickOutside as vClickOutside } from 'element-plus'
import { Delete, Download, Plus, ZoomIn } from '@element-plus/icons-vue'
import type { UploadProps } from 'element-plus'
const props = defineProps(['formState', 'formData'])
const emit = defineEmits(['update:formState'])

import constant from '@/utils/constant'

const action = ref(constant.uploadUrl)

const beforeUpload = file => {
	const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/jpg'
	if (!isJpgOrPng) {
		ElMessage.error('只支持JPG、PNG格式!')
		return Promise.reject()
	}
	const isLt2M = file.size / 1024 / 1024 > 2
	if (isLt2M) {
		ElMessage.error('图片大小不能超过2MB!')
		return Promise.reject()
	}
}
const fileList = ref([])
const loading = ref<boolean>(false)
const imageUrl = ref<string>('')
const handleChange = (info, key) => {
	if (info.file.status === 'uploading') {
		loading.value = true
		return
	}
	if (info.file.status === 'done') {
		// Get this url from response in real world.
		const src = info.file.response.data
		// console.log({ ...props.formState, [key]: src })
		emit('update:formState', { ...props.formState, [key]: src })
		loading.value = false
	}
	if (info.file.status === 'error') {
		loading.value = false
		ElMessage.error('upload error')
	}
}

const handleAvatarSuccess: UploadProps['onSuccess'] = (res, file) => {
	if (res.code !== 0) {
		ElMessage.error('上传失败：' + res.message)
		return false
	}

	props.formState['backgroundImage'] = res.data.url
	emit('update:formState', { ...props.formState })
	// dataForm.name = res.data.name
	// dataForm.type = res.data.suffix
	// dataForm.fileUrl = res.data.url
	// dataForm.size = res.data.size
}

const handleRemove: UploadProps['onRemove'] = (uploadFile, uploadFiles) => {
	props.formState['backgroundImage'] = ''
	emit('update:formState', { ...props.formState })
}

const Form: any = ref(null)

const submit = async () => {
	return new Promise((resolve, reject) => {
		Form.value.validate((valid, fields) => {
			if (valid) {
				console.log('submit!')
				resolve()
			} else {
				console.log('error submit!', fields)
				reject(fields)
			}
		})
	})
}

const reset = () => {
	console.log('reset')
	Form.value.resetFields()
}

const findTextLoop = (Data, key, value) => {
	let item
	for (let v of Data) {
		if (v[key] == value) {
			item = v
			break
		} else if (v.children && v.children.length) {
			const i = findTextLoop(v.children, key, value)
			if (i) {
				item = i
				break
			}
		}
	}
	// console.log(item)
	return item
}

const findText = (Data, key, value, label) => {
	// console.log(Data, key, value)
	if (!value) {
		return ''
	}
	if (!Data.length) {
		return ''
	}
	const item = findTextLoop(Data, key, value)
	if (item) {
		return item[label]
	} else {
		return ''
	}
}

defineExpose({
	submit,
	reset
})
</script>

<style lang="scss" scoped>
.avatar-uploader .avatar {
	width: 178px;
	height: 178px;
	display: block;
}
.avatar-uploader {
	border: 1px dashed var(--el-border-color);
	border-radius: 6px;
	cursor: pointer;
	position: relative;
	overflow: hidden;
	transition: var(--el-transition-duration-fast);
}

.avatar-uploader:hover {
	border-color: var(--el-color-primary);
}

.el-icon.avatar-uploader-icon {
	font-size: 28px;
	color: #8c939d;
	width: 178px;
	height: 178px;
	text-align: center;
}
:deep(.ant-upload-select-picture-card) {
	height: auto !important;
	.ant-upload {
		min-height: 100px !important;
	}
}
// .avatar-uploader > .ant-upload {
// 	width: 128px;
// 	height: 128px;
// }
.ant-upload-select-picture-card i {
	font-size: 32px;
	color: #999;
}

.ant-upload-select-picture-card .ant-upload-text {
	margin-top: 8px;
	color: #666;
}

.el-upload-list__item-delete {
	display: inline-block;
	z-index: 9999;
	left: 158px;
	top: 5px;
}
</style>
